#include"tcpsocket.hpp"
#include<signal.h>
#include"cala.hpp"
using namespace std;

//多进程
void create_worker(TcpSocket &sock){
    pid_t pid=fork();
    if(pid<0){
        sock.Close();
        return;
    }
    else if(pid==0){//子进程只负责与指定客户端通信
        while(1){
        //收发数据
        string body;
        bool ret=sock.Recv(&body);
        if(ret==false){
            sock.Close();
            continue;
        }
        cout<<"client say:"<<body<<endl;
        body.clear();
        cout<<"server say:";
        fflush(stdout);
        cin>>body;
        ret=sock.Send(body);
        if(ret==false){
            break;
            }
        }
        //子进程循环完毕就退出，不能让子进程继续运行
        sock.Close();//子进程关闭套接字
        exit(-1);
    }
    //父子进程数据独有，因此父进程关闭，并不影响子进程
    //并且父进程不关闭反而会造成资源泄漏，因为父进程不与客户端通信,只获取新建连接
    sock.Close();//父进程关闭套接字
}
void *thread_entry(void *arg){
    //TcpSocket sock((int)arg);
    TcpSocket sock((long)arg);
    while(1){
        int fd=sock.Fd();
        cala_t tmp;
        ssize_t s=recv(fd,&tmp,sizeof(cala_t),0);
        if(s==0)
        {
            break;
        }
        else if(s<0)
        {
            break;
        }
        int result=-1;
        if(tmp._op=='+'){
            result=tmp._num1+tmp._num2;
        }
        send(fd,&result,sizeof(int),0);
    }
    sock.Close();
    return NULL;
}
//多线程
void create_thread(TcpSocket &sock){//线程描述符不能关闭，否则影响进程内的其它线程
    pthread_t tid;
    int ret=pthread_create(&tid,NULL,thread_entry,(void*)sock.Fd());
    if(ret!=0){
        cout<<"create thread error"<<endl;
        sock.Close();
        return;
    }
    pthread_detach(tid);//分离线程-退出自动释放所有资源,不需要被等待
}
#define CHECK_RET(r) if((r) == false){return -1;}
int main(int argc,char *argv[]){
    if(argc!=3){
        cout<<"usage:./tcp_srv 127.168.2.2 9000\n";
        return -1;
    }
    //显式忽略SIGCHLD信号处理，当子进程退出后自动释放资源
    signal(SIGCHLD,SIG_IGN);
    string ip=argv[1];
    uint16_t port=stoi(argv[2]);
    TcpSocket lsn_sock;
    //创建套接字
    CHECK_RET(lsn_sock.Socket());
    //绑定地址信息
    CHECK_RET(lsn_sock.Bind(ip,port));
    //开始监听
    CHECK_RET(lsn_sock.Listen());
    while(1){
    //获取新建连接
    TcpSocket new_sock=lsn_sock.Accept();//这是个阻塞接口
    if(new_sock.Available()==false){
        continue;
    }
    //create_worker(new_sock);
    create_thread(new_sock);
    }
    //关闭套接字
    // lsn_sock.Close();
    return 0;
}